!pr0
!lm12
!rm75
Base Address Calculation...................Bob Sander-Cederlof

I believe that Steve Wozniak was the first to use the tricks in a microcomputer, back in 1976 and 1977.  All of the other designs I recall either used the more expensive static RAM, or used a complex circuit to refresh dynamic RAM arrays.  Steve's design allowed the use of dynamic RAM without any separate circuitry for refresh.

Dynamic RAM needs refreshing because each bit cell is really only a capacitor, and the charge runs out after a few milliseconds.  By reading each bit and re-writing it every few milliseconds, the data in memory is maintained as long as you like.  Each 16384-bit RAM-chip is organized in 128 rows by 128 columns of bytes, and the chips are designed so that merely addressing each row often enough will keep the bits fresh as a daisy.  Steve hooked up the Apple so that the process of keeping data displayed on the screen also ran through all the row addresses.

His second trick was to keep the screen (and therefore the RAM) happy without stealing any time from the CPU.  He did this by using alternate half cycles of the clock.  The one-megahertz clock runs the 6502 every other half cycle, and the screen gets its whacks at memory in between.

What has all the above to do with an article titled "Base Address Calculation"?  Well, I'm getting to that.  In order to address each row often enough, Steve re-arranged the address bits in a rather complicated way.  As the screen is refreshed, scan-line by scan-line, bytes are read from RAM in an order that assures every RAM row is accessed about every 2 milliseconds.  [ For the exact details of this process, see  Winston Gayler's "Apple II Circuit Description", pages 41-57. ]

All this boils down to a need to go through a complicated calculation to convert a display line number into a base address in RAM.  The process is implemented for the text screen at $FBC1 in the monitor ROM; for the lo-res graphics screen at $F847 in the monitor ROM; for the hi-res graphics screen at $F417 in the Applesoft ROM.

If we represent the 8-bit value for the line number on the text screen as "000abcde", the base calculation computes the address in RAM for the first character on that line and stores the result in two bytes at $28 and $29 in the form "000001cd eabab000".  The two bits "ab" may have values "00", "01", or "10" for lines 0-7, 8-15, and 16-23 respectively.  The "abab000" part of the least significant byte of the base address represents "ab" times 40.  Remember there are 40 characters on a line?

The hi-res base address calculation is more complicated, but it really the same thing.  If we think of a text line as being made up of 8 hi-res lines, both calculations ARE the same.  Except that the lo-res RAM starts at $400, and the hi-res starts at $2000.  A hi-res line number runs from 0 through 191, or $00 - $BF.  If we visualize it as "abcdefgh", the base address calculation merely re-arranges the bits to "001fghcd eabab000".  Note that if we multiply the text line number by 8 and run it through the hi-res calculation we will get "001000cd eabab000" which is correct except for starting at $2000 rather than $400.

The hi-res calculation inside Applesoft takes 33 bytes and 61 cycles.  Harry Cheung, who lives in Onitsha, Nigeria, wrote a letter to Call APPLE (page 70, July, 1983) to present his shorter, faster version.  Harry did it in 25 bytes and only 46 cycles (one more byte and 6 more cycles if you count the RTS, but I didn't count an RTS in the Applesoft version).  Here is Harry's code, with my comments.




















I need to point out several things here.  Harry used page zero locations $00 and $01 for the resulting base address.  If you want to use his program with Applesoft, change them to $26 and $27.  Harry save the line number temporarily in the Y-register.  If the Y-register is already holding something important (it is in the Applesoft case), you can substitute PHA and PLA for the TAY and TYA above.  Same number of bytes, but 3 cycles longer.

If you want REAL speed, and can spare a few more bytes, you need to pre-compute all the base addresses and store them in a table.  Then you can use the line number as an index into the table and do a base address TRANSLATION in just a few cycles.  For example, assume you store all the low-order bytes in a 192-byte table called LO.BASE, and similarly the high-order bytes at HI.BASE.  If you get the line number in the Y-register, then you can convert the line number to a base address like this:

!lm+5
       LDA LO.BASE,Y
       STA $26
       LDA HI.BASE,Y
       STA $27
!lm-5

That takes 10 bytes of program, 384 bytes of table, and only 14 to 16 cycles.  I say 14 to 16, because it depends on whether either or both of the two tables cross page boundaries.  If they each are entirely within a memory page, 14 cycles.

Now here is a little piece of code I wrote to test out Harry's calculator.  It runs through each of the 192 lines and prints out the line number, an equal sign, the base address, and a space for each line (all in hex).
















The monitor address $FDD3 is not a labelled entry point, but I think it will probably stay consistent in future editions of the Apple ROMs.  It saves whatever is in the A-register, prints "=", restores the A-register, and falls into $FDDA.  The routine at $FDDA prints the contents of A in hex.

Just for fun I also wrote some new versions of the text base address calculator.  One of them is shorter but takes more time, and the other is longer but takes  less time.  Oh well, can't win every race!   Here are listings of them both, followed by a commented listing of the Applesoft hi-res calculator.
!np









































By the way, if you want to see the WHOLE thing...a commented listing of the entire Applesoft ROM, we have it on disk in format for the S-C Macro Assembler.
